﻿//===============================================================================
// Microsoft patterns & practices Enterprise Library
// Validation Application Block
//===============================================================================
// Copyright © Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System;
using System.Collections.Generic;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Properties;
using System.Globalization;

namespace Microsoft.Practices.EnterpriseLibrary.Validation.Validators
{
	/// <summary>
	/// Aggregates a set of <see cref="Validator"/> instances, performing validation by allowing each validator to perform its own.
	/// </summary>
	/// <remarks>
	/// Validation results are logged only if all composed validators log results.
	/// </remarks>
	[ConfigurationElementType(typeof(OrCompositeValidatorData))]
	public class OrCompositeValidator : Validator
	{
		private IEnumerable<Validator> validators;

		/// <summary>
		/// <para>Initializes a new instance of the <see cref="OrCompositeValidator"/> class.</para>
		/// </summary>
		/// <param name="validators">The validators to be composed by the created instance.</param>
		public OrCompositeValidator(params Validator[] validators)
			: this(null, validators)
		{ }

		/// <summary>
		/// <para>Initializes a new instance of the <see cref="OrCompositeValidator"/> class.</para>
		/// </summary>
		/// <param name="messageTemplate"></param>
		/// <param name="validators">The validators to be composed by the created instance.</param>
		public OrCompositeValidator(string messageTemplate, params Validator[] validators)
			: base(messageTemplate, null)
		{
			this.validators = validators;
		}

		/// <summary>
		/// Implements the validation logic for the receiver, invoking validation on the composed validators.
		/// </summary>
		/// <param name="objectToValidate">The object to validate.</param>
		/// <param name="currentTarget">The object on the behalf of which the validation is performed.</param>
		/// <param name="key">The key that identifies the source of <paramref name="objectToValidate"/>.</param>
		/// <param name="validationResults">The validation results to which the outcome of the validation should be stored.</param>
		/// <remarks>
		/// The results the generated by the composed validators are logged to <paramref name="validationResults"/>
		/// only if all the validators generate results.
		/// </remarks>
		public override void DoValidate(object objectToValidate,
			object currentTarget,
			string key,
			ValidationResults validationResults)
		{
			List<ValidationResult> childrenValidationResults = new List<ValidationResult>();

			foreach (Validator validator in this.validators)
			{
				ValidationResults childValidationResults = new ValidationResults();
				validator.DoValidate(objectToValidate, currentTarget, key, childValidationResults);
				if (childValidationResults.IsValid)
				{
					// no need to query the rest of the validators
					return;
				}

				childrenValidationResults.AddRange(childValidationResults);
			}

			LogValidationResult(validationResults,
				GetMessage(objectToValidate, key),
				currentTarget, 
				key,
				childrenValidationResults);
		}

		/// <summary>
		/// Gets the message template to use when logging results no message is supplied.
		/// </summary>
		/// <remarks>
		/// This validator does not log messages of its own.
		/// </remarks>
		protected override string DefaultMessageTemplate
		{
			get { return Resources.OrCompositeValidatorDefaultMessageTemplate; }
		}

        /// <summary>
        /// Child validators that are being Or'red together.
        /// </summary>
        public IEnumerable<Validator> Validators
		{
			get
			{
				return this.validators;
			}
		}
	}
}
